#pragma once

#include "JsiHostObject.h"

#include "Declaration.h"
#include "DeclarationContext.h"

#include <memory>
#include <string>
#include <utility>
#include <vector>

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdocumentation"

#include "include/core/SkCanvas.h"
#include "include/core/SkPaint.h"
#include "include/core/SkRefCnt.h"

#pragma clang diagnostic pop

namespace RNSkia {
class PaintProps;
class JsiDomNode;

class DomRenderContext {
public:
    float getScaledWidth()
    {
        return _scaledWidth;
    }
    float getScaledHeight()
    {
        return _scaledHeight;
    }

    void setScaledWidth(float v)
    {
        _scaledWidth = v;
    }
    void setScaledHeight(float v)
    {
        _scaledHeight = v;
    }

    void setRequestRedraw(std::function<void()> &&requestRedraw)
    {
        _requestRedraw = std::move(requestRedraw);
    }

    const std::function<void()> &getRequestRedraw()
    {
        return _requestRedraw;
    }

private:
    float _scaledWidth = -1;
    float _scaledHeight = -1;
    std::function<void()> _requestRedraw;
};

class DrawingContext : public DomRenderContext, public std::enable_shared_from_this<DrawingContext> {
public:
    /* *
     Creates a root drawing context with paint and opacity
     */
    DrawingContext();

    /* *
     Creates a drawing context with the given paint as its starting paint object
    */
    explicit DrawingContext(std::shared_ptr<SkPaint> paint);

    /* *
     Factory for saving/restoring the context for a node
     */
    bool saveAndConcat(PaintProps *paintProps, const std::vector<std::shared_ptr<JsiDomNode>> &children,
        std::shared_ptr<SkPaint> paintCache);
    void restore();

    /* *
     Returns true if the current cache is changed
     */
    bool isChanged();

    /* *
     Get/Sets the canvas object
     */
    SkCanvas *getCanvas();

    /* *
     Sets the canvas
     */
    void setCanvas(SkCanvas *canvas);

    /* *
     Gets the paint object
     */
    std::shared_ptr<SkPaint> getPaint();

    /*
     Returns the root declaratiins object
     */
    DeclarationContext *getDeclarationContext()
    {
        return _declarationContext.get();
    }

private:
    void save();

    explicit DrawingContext(const char *source);
    SkCanvas *_canvas = nullptr;
    std::vector<std::shared_ptr<SkPaint>> _paints;
    std::unique_ptr<DeclarationContext> _declarationContext;
};
} // namespace RNSkia
